package com.ksd.modules.rbac.sysuser.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ksd.common.contants.CacheConstants;
import com.ksd.common.core.exception.KsdBusinessException;
import com.ksd.common.enums.DeletedEnums;
import com.ksd.commons.BaseServiceImpl;
import com.ksd.convert.CopyConvertUtils;
import com.ksd.modules.rbac.api.entity.SysApis;
import com.ksd.modules.rbac.api.mapper.SysRoleApisMapper;
import com.ksd.modules.rbac.menus.entity.SysMenus;
import com.ksd.modules.rbac.menus.mapper.SysRoleMenusMapper;
import com.ksd.modules.rbac.roles.entity.SysRoles;
import com.ksd.modules.rbac.roles.mapper.SysUserRolesMapper;
import com.ksd.modules.rbac.sysuser.constants.UserConstants;
import com.ksd.modules.rbac.sysuser.context.UserLoginContext;
import com.ksd.modules.rbac.sysuser.entity.SysUsers;
import com.ksd.modules.rbac.sysuser.mapper.SysUsersMapper;
import com.ksd.modules.rbac.sysuser.po.SysUsersSavePO;
import com.ksd.modules.rbac.sysuser.po.SysUsersSearchPO;
import com.ksd.modules.rbac.sysuser.service.ISysUsersService;
import com.ksd.modules.system.entity.AdminSystem;
import com.ksd.modules.system.service.IAdminSystemService;
import com.ksd.modules.system.service.IAdminSystemUserService;
import com.ksd.utils.UUIDUtil;
import com.ksd.utils.jwt.JwtUtil;
import com.ksd.utils.pwd.PasswordUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 系统用户表 服务实现类
 * </p>
 *
 * @author Auto Generator
 * @since 2023-08-13
 */
@Service
public class SysUsersService extends BaseServiceImpl<SysUsersMapper, SysUsers> implements ISysUsersService {

    @Autowired
    private CacheManager cacheManager;
    @Resource
    private SysRoleMenusMapper sysRoleMenusMapper;
    @Resource
    private SysRoleApisMapper sysRoleApisMapper;
    @Resource
    private SysUserRolesMapper sysUserRolesMapper;
    @Resource
    private IAdminSystemUserService adminSystemUserService;
    @Resource
    private IAdminSystemService adminSystemService;
    @Value("${verifyLoginVerificationCode:}")
    private String verifyLoginVerificationCode;


    /**
     * 用户登录业务实现
     * <p>
     * 需要实现的功能：
     * 1、用户的登录信息校验
     * 2、生成一个具有时效性的accessToken
     * 3、将accessToken缓存起来，去实现单机登录
     *
     * @param userLoginContext
     * @return
     */
    @Override
    public String login(UserLoginContext userLoginContext) {
        checkLoginInfo(userLoginContext);
        checkBindPlatformSystem(userLoginContext);
        generateAndSaveAccessToken(userLoginContext);
        getUserRoleMenuApisInfo(userLoginContext);
        return userLoginContext.getAccessToken();
    }

    private  void checkBindPlatformSystem(UserLoginContext userLoginContext){
        // 查询默认系统
        if(!userLoginContext.getSysUsers().getId().equals(1L)) {
            List<AdminSystem> adminSystems = adminSystemUserService.findAdminSystemAll(userLoginContext.getSysUsers().getId());
            if (CollectionUtils.isEmpty(adminSystems)) {
                throw new KsdBusinessException("请联系管理员绑定系统，在进行操作!!!");
            }
            userLoginContext.setAdminSystems(adminSystems);
        }else{
            List<AdminSystem> adminSystems = adminSystemService.findAdminSystemAll();
            userLoginContext.setAdminSystems(adminSystems);
        }
    }

    private void getUserRoleMenuApisInfo(UserLoginContext userLoginContext) {
        List<SysRoles> roles = sysUserRolesMapper.findRoles(userLoginContext.getSysUsers().getId());
        List<SysApis> roleApis = new ArrayList<>();
        List<SysMenus> roleMenus = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(roles)) {
            roleApis = sysRoleApisMapper.findRoleApis(roles.get(0).getId());
            roleMenus = this.tree(sysRoleMenusMapper.findRoleMenus(roles.get(0).getId()));
        }
        userLoginContext.setRoles(roles);
        userLoginContext.setMenus(roleMenus);
        userLoginContext.setPermissions(roleApis);
    }


    private List<SysMenus> tree(List<SysMenus> list){
        List<SysMenus> resultList = new ArrayList<>();
        for (SysMenus result : list) {
            if (result.getParentId() == 0L) {
                //调用方法给子类添加数据
                resultList.add(getMenuTree(result, list));
            }
        }
        return resultList;
    }

    private SysMenus getMenuTree(SysMenus result, List<SysMenus> list) {
        for (SysMenus menu : list) {
            //如果父类主键等于传过来实体类的ID
            if (menu.getParentId() == result.getId()) {
                if (result.getChildren() == null) {
                    result.setChildren(new ArrayList<>());
                }
                // 递归调用
                result.getChildren().add(getMenuTree(menu, list));
            }
        }
        return result;
    }

    /**
     * 生成并保存登陆之后的凭证
     *
     * @param userLoginContext
     */
    private void generateAndSaveAccessToken(UserLoginContext userLoginContext) {
        SysUsers entity = userLoginContext.getSysUsers();
        String accessToken = JwtUtil.generateToken(entity.getUsername(),
                UserConstants.LOGIN_USER_ID, entity.getId(), UserConstants.ONE_DAY_LONG);
        Cache cache = cacheManager.getCache(CacheConstants.MAYA_CHIGUA_CACHE_NAME);
        cache.put(UserConstants.USER_LOGIN_PREFIX + entity.getId(), accessToken);
        userLoginContext.setAccessToken(accessToken);
    }


    /**
     * 校验用户名密码
     *
     * @param userLoginContext
     */
    private void checkLoginInfo(UserLoginContext userLoginContext) {
        String code = userLoginContext.getCode();
        String username = userLoginContext.getAccount();
        String password = userLoginContext.getPassword();

        if (!"close".equals(verifyLoginVerificationCode)) {
            if (!code.equalsIgnoreCase(userLoginContext.getSessionCode())) {
                throw new KsdBusinessException("输入验证码有误");
            }
        }

        SysUsers sysUsers = getSysUsersByAccount(username);
        if (Objects.isNull(sysUsers)) {
            throw new KsdBusinessException("账号不存在");
        }

        String salt = sysUsers.getSlat();
        String encPassword = PasswordUtil.encryptPassword(salt, password);
        String dbPassword = sysUsers.getPassword();
        if (!Objects.equals(encPassword, dbPassword)) {
            throw new KsdBusinessException("密码信息不正确");
        }
        userLoginContext.setSysUsers(sysUsers);
    }


    /**
     * 通过用户名称获取用户实体信息
     *
     * @param username
     * @return
     */
    public SysUsers getSysUsersByAccount(String username) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("account", username);
        return getOne(queryWrapper);
    }


    /**
     * 用户退出登录
     *
     * @param userId
     */
    @Override
    public void exit(Long userId) {
        try {
            Cache cache = cacheManager.getCache(CacheConstants.MAYA_CHIGUA_CACHE_NAME);
            cache.evict(UserConstants.USER_LOGIN_PREFIX + userId);
        } catch (Exception ex) {
            throw new KsdBusinessException("用户退出登录失败!");
        }
    }


    @Override
    public Page<SysUsers> findSysUsers(SysUsersSearchPO sysApisSearchPO) {
        QueryWrapper<SysUsers> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("t1.is_deleted", DeletedEnums.UN_DELETED.getCode());
        queryWrapper.eq(Objects.nonNull(sysApisSearchPO.getStatus()), "t1.status", sysApisSearchPO.getStatus());
        if (StringUtils.isNotEmpty(sysApisSearchPO.getKeyword())) {
            queryWrapper.and(c -> c.like("t1.username", sysApisSearchPO.getKeyword())
                    .or().like("t1.account", sysApisSearchPO.getKeyword())
                    .or().like("t1.phone", sysApisSearchPO.getKeyword())
                    .or().like("t1.email", sysApisSearchPO.getKeyword()));
        }
        queryWrapper.orderByAsc("t1.create_time");
        // 查询返回
        Page<SysUsers> page = new Page<>(sysApisSearchPO.getPageNo(), sysApisSearchPO.getPageSize());
        return this.baseMapper.findSysUsers(page, queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveUpdateSysUsers(SysUsersSavePO sysUsersSavePO) {
        if (sysUsersSavePO != null && sysUsersSavePO.getId() == null) {
            if (StringUtils.isNotEmpty(sysUsersSavePO.getPassword())) {
                String salt = UUIDUtil.getUUID();
                String encPassword = PasswordUtil.encryptPassword(salt, sysUsersSavePO.getPassword());
                sysUsersSavePO.setSlat(salt);
                sysUsersSavePO.setUuid(salt);
                sysUsersSavePO.setPassword(encPassword);
            }
        }
        SysUsers mayaSysUsers = CopyConvertUtils.copyProperties(sysUsersSavePO, SysUsers.class);
        return this.saveOrUpdate(mayaSysUsers);
    }

    @Override
    public boolean updatePasswordDefault(Long userId) {
        SysUsers sysUsers = this.getById(userId);
        if(Objects.nonNull(sysUsers)) {
            String slat = UUIDUtil.getUUID();
            String encPassword = PasswordUtil.encryptPassword(slat, UserConstants.DEFAULT_PASSWORD);
            sysUsers.setSlat(slat);
            sysUsers.setPassword(encPassword);
            return this.updateById(sysUsers);
        }
        return false;
    }

    @Override
    public boolean deleteSysUsersById(Long id) {
        return this.removeById(id);
    }

    @Override
    public SysUsers getSysUsersById(Long id) {
        return this.getById(id);
    }

    /**
     * 接触绑定老师关系
     * @param id
     * @return
     */
    @Override
    public  Boolean unbindTeacherFlag(Long id){
        SysUsers sysUsers = new SysUsers();
        sysUsers.setId(id);
        sysUsers.setTeacherId(0L);
        sysUsers.setTeacherNickname("");
        sysUsers.setTeacherUsername("");
        sysUsers.setTeacherAvatar("");
        sysUsers.setTeacherUuid("");
        return this.updateById(sysUsers);
    }

}
